package com.yunwaikeji.gy_tool_library.utils.file;

import android.os.Handler;
import android.os.Looper;

import com.yunwaikeji.gy_tool_library.task.GYAsyncTask;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class GYFileWriteTask extends GYAsyncTask<GYFileWriteTask, Object, Object, Object> {
    private File writeFile;
    private InputStream inputStream;
    private long nowBytes = 0;
    private long totalBytes;
    private int cacheSize = 10 * 1024;
    private GYFileLoadListener fileLoadListener;
    private boolean isCompleted = false;
    private boolean reStart = false;

    public GYFileWriteTask setReStart(boolean reStart) {
        this.reStart = reStart;
        return getTask();
    }

    public GYFileWriteTask setFileLoadListener(GYFileLoadListener fileLoadListener) {
        this.fileLoadListener = fileLoadListener;
        return this;
    }

    public GYFileWriteTask setFile(String file) {
        try {
            inputStream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return this;
    }

    public GYFileWriteTask setFile(File file) {
        return setFile(file.getPath());
    }

    public GYFileWriteTask setWriteFile(File writeFile) {
        this.writeFile = writeFile;
        return this;
    }

    public GYFileWriteTask setWriteFile(String writeFile) {
        return setWriteFile(new File(writeFile));
    }

    public GYFileWriteTask setInputStream(InputStream inputStream) {
        this.inputStream = inputStream;
        return this;
    }

    public GYFileWriteTask setNowBytes(long nowBytes) {
        this.nowBytes = nowBytes;
        return this;
    }

    public long getNowBytes() {
        return nowBytes;
    }

    public GYFileWriteTask setTotalBytes(long totalBytes) {
        this.totalBytes = totalBytes;
        return this;
    }

    public long getTotalBytes() {
        return totalBytes;
    }

    public long getSecondBytes() {
        return secondBytes;
    }

    public GYFileWriteTask setCacheSize(int cacheSize) {
        this.cacheSize = cacheSize;
        return this;
    }

    private boolean paused = false;

//    public GYFileWriteBuilder paused() {
//        paused = true;
//        return this;
//    }

    @Override
    public void stop() {
        paused = true;
        nowBytes = 0;
        super.stop();
    }

    @Override
    public void onLoading(long nowBytes, long totalBytes, long secondBytes) {
        if (fileLoadListener != null) {
            if (isResponseMainThread()) {
                mainThread(() -> fileLoadListener.loading(nowBytes, totalBytes, secondBytes));
            } else {
                fileLoadListener.loading(nowBytes, totalBytes, secondBytes);
            }
        }
    }

    @Override
    public void onSuccess(Object response) {
        if (fileLoadListener != null) {
            if (isResponseMainThread()) {
                mainThread(() -> fileLoadListener.success((String) response));
            } else {
                fileLoadListener.success((String) response);
            }
        }
    }

    @Override
    public Integer start() {
        if (writeFile == null) {
            onError("writeFile为空");
            return null;
        }
        paused = false;
        return super.start();
    }

    private long secondBytes = 0;
    private long lastBytes = 0;
    private final Handler handler = new Handler(Looper.getMainLooper());
    private final Runnable runnable = new Runnable() {
        @Override
        public void run() {
            secondBytes = nowBytes - lastBytes;
            lastBytes = nowBytes;
            if (nowBytes == totalBytes) {
                secondBytes = 0;
            }
            if (nowBytes < totalBytes) {
                handler.postDelayed(this, 1000);
            } else {
                handler.removeCallbacks(this);
            }
        }
    };

    @Override
    public void onError(String error) {
        super.onError(error);
        if (!isStarting()) {
            onFinish();
        }
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        if (fileLoadListener != null) {
            fileLoadListener.start();
        }
    }


    @Override
    protected Object doInBackground() {
        write();
        return null;
    }

    @Override
    protected void onPostExecute(Object o) {
        super.onPostExecute(o);
        onFinish();
    }

    private void write() {
        if (totalBytes == -1) {
            totalBytes = 0;
        }
        handler.post(runnable);
        if (!reStart && writeFile.exists() && writeFile.length() == totalBytes) {
            nowBytes = totalBytes;
            secondBytes = 0;
            if (fileLoadListener != null) {
                onLoading(nowBytes, totalBytes, secondBytes);
                onSuccess(writeFile.getPath());
            }
            return;
        }
        FileOutputStream fileOutputStream;
        try {
            fileOutputStream = new FileOutputStream(writeFile);
            byte[] b = new byte[cacheSize];
            int len;
            while ((len = inputStream.read(b)) != -1) {
                if (isCanceled()) {
                    return;
                }
                if (paused) {
                    paused = false;
                    break;
                }
                fileOutputStream.write(b, 0, len);
                nowBytes += len;
                if (nowBytes == totalBytes) {
                    secondBytes = 0;
                }
                if (fileLoadListener != null) {
                    onLoading(nowBytes, totalBytes, secondBytes);
                    if (nowBytes == totalBytes && !isCompleted) {
                        isCompleted = true;
                        onSuccess(writeFile.getPath());
                    }
                }
            }
            if (totalBytes <= 0 && fileLoadListener != null) {
                totalBytes = nowBytes;
                secondBytes = 0;
                onLoading(nowBytes, totalBytes, secondBytes);
                onSuccess(writeFile.getPath());
            }
            inputStream.close();
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            onError("FileNotFoundException：" + e);
        } catch (IOException e) {
            onError("IOException：" + e);
        }
    }

    private void onFinish() {
        if (fileLoadListener != null) {
            fileLoadListener.finish();
        }
    }
}
